# BSD3.0
# cili@163.com

import tkinter as tk
from tkinter import ttk, simpledialog, messagebox
import random, re


class App(tk.Tk):
    TITLE = 'IP地址仿真实验'
    IP_PR = '192.168.1.'
    BUTTON_WIDTH = 22
    NUMS = 20
    COLORS = ['SystemButtonFace', 'lightgray', 'lightgreen', 'lightblue', 'brown']
    COMPUTER_NAMES = ['学生用机', '默认网关', '教师用机', '广播地址']
    STRING_IP_PATTERN = r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
    IP_P = re.compile(STRING_IP_PATTERN)
    TIPS = ['单击学生用机，可以修改它的IP地址']

    def __init__(self):
        super().__init__()
        self.title(self.TITLE)

        computers = [(self.COMPUTER_NAMES[0], f'{self.IP_PR}{n}') for n in random.sample(range(11, 254), self.NUMS)] + [
            (self.COMPUTER_NAMES[1], f'{self.IP_PR}1'), None, (self.COMPUTER_NAMES[2], f'{self.IP_PR}10'), None,
            (self.COMPUTER_NAMES[3], f'{self.IP_PR}255')]
        flags =[True] * self.NUMS +[False] * 5
        self.buttons =[self.create_button(index, computer, flag=flag) for index, (computer, flag) in
            enumerate(zip(computers, flags))]
        self.display_buttons(-1)

        tip_label = ttk.Label(self, text=self.TIPS[0])
        tip_label.grid(row=self.NUMS // 5 + 2, column=0, columnspan=5, sticky="ew", pady=(5, 5), padx=(5, 0))
        self.center_window()
        self.resizable(False, False)

    def create_button(self, index, computer, flag=True):
        if computer is None: return None
        title = f'{computer[0]}：{index + 1}' if flag else f'{computer[0]}'
        text = f'{title}\n\nIP地址：{computer[1]:>15}'
        row = index // 5 + 1 if flag else 0
        column = index % 5 if flag else (index - self.NUMS) % 5
        pady = 5 if flag else 15
        command = self.modify_ip if flag else self.show_message
        button = tk.Button(self, text=text, command=lambda: command(index), width=self.BUTTON_WIDTH)
        button.grid(row=row, column=column, sticky="nsew", padx=5, pady=pady)
        return [button, computer[1], index, computer[0]]

    def center_window(self):
        self.update_idletasks()
        x = (self.winfo_screenwidth() - self.winfo_reqwidth()) // 2
        y = (self.winfo_screenheight() - self.winfo_reqheight()) // 2
        self.geometry(f'+{x}+{y}')
        self.deiconify()

    def show_message(self, x):
        btn = self.buttons[x]
        messagebox.showwarning('警告', f'{btn[3]}\n\nIP地址：{btn[1]:<15}不可修改！')

    def modify_ip(self, x):
        btn = self.buttons[x]
        self.display_buttons(x)
        btn[0].config(bg=self.COLORS[3])
        new_ip = simpledialog.askstring('修改', f'{btn[3]}：{btn[2] + 1}\n原IP地址：{btn[1]:<35}   \n新IP地址:')
        if not new_ip: return
        if len(new_ip.strip()) == 0: return
        if not self.IP_P.match(new_ip):
            messagebox.showerror('错误', f'IP地址 {new_ip} 不合法！')
            return
        new_ip = ".".join(str(int(part)) for part in new_ip.split("."))

        if not new_ip or new_ip == btn[1]:
            self.display_buttons(x)
            return

        ip_last = new_ip.split('.')[-1]
        if ip_last == '0':
            messagebox.showwarning('警告', f'主机号为 {ip_last} 时，IP地址为保留地址，不可设置！')
            return
        if ip_last in ['1', '255']:
            messagebox.showwarning('警告', f'主机号为 {ip_last} 时，IP地址一般为保留地址！')
        elif any(item[1] == new_ip for item in self.buttons if item):
            messagebox.showwarning('警告', '地址冲突！')
        elif self.IP_PR not in new_ip:
            messagebox.showwarning('警告', f'请检查 {new_ip} 的网络号！')
        btn[1] = new_ip
        btn[0].config(text=f'{btn[3]}：{btn[2] + 1}\n\nIP地址：{btn[1]:<15}')
        self.display_buttons(x)

    def display_buttons(self, x):
        bgs = [self.COLORS[1] if btn and btn[2] >= self.NUMS else self.COLORS[0] for btn in self.buttons]
        bgs[x] = self.COLORS[2] if x > 0 else bgs[x]
        [btn[0].config(bg=bg) for btn, bg in zip(self.buttons, bgs) if btn]
        data = {}
        [data.setdefault(item[1], []).append(item) for item in self.buttons if item]
        items = [value for key, value in data.items() if len(value) > 1]
        [btn[0].config(bg=self.COLORS[-1]) for item in items for btn in item]
        [btn[0].config(bg=self.COLORS[-1]) for btn in self.buttons if btn and self.IP_PR not in btn[1]]


if __name__ == "__main__":
    app = App()
    app.mainloop()
